package com.ymt.bpm.web.rest.platform.profile;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ymt.bpm.appboot.BpmpProperties;
import com.ymt.bpm.dao.MDao;
import com.ymt.bpm.dao.Mapper;
import com.ymt.bpm.engine.EngineConst;
import com.ymt.bpm.model.*;
import com.ymt.bpm.model.Const.Oplog;
import com.ymt.bpm.service.platform.log.OpLogService;
import com.ymt.bpm.service.platform.profile.AvatarService;
import com.ymt.bpm.service.platform.profile.UserProfileService;
import com.ymt.bpm.util.AES;
import com.ymt.bpm.util.Const;
import com.ymt.bpm.util.DateUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.env.Environment;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

/**
 * Created by Johnny on 2017/2/2.
 * For user profile self-management
 */
@RestController
@EnableConfigurationProperties(BpmpProperties.class)
public class UserProfileResource {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private BpmpProperties bpmp;

    @Autowired
    private Environment env;

    @Autowired
    private MDao dao;

    @Autowired
    private UserProfileService ups;

    @Autowired
    private OpLogService oplog;

    @Autowired
    private AvatarService avs;

    /**
     * Get usr profile info, used in user management
     * @param request
     * @param userId
     * @param withExt
     * @return
     */
    @RequestMapping(value="/api/v1/userInfo/{userId}", method= RequestMethod.GET)
    public JSONObject get(HttpServletRequest request,
                          @PathVariable("userId")String userId,
                          @RequestParam("withExt")Boolean withExt) {
        Map<String, String> userDetail = (Map<String, String>)SecurityContextHolder.getContext().getAuthentication().getDetails();
        String tenantId = userDetail.get(Const.TENANT_ID);
        if(log.isDebugEnabled()) {
            log.debug("get tenantId="+tenantId);
            log.debug("get userId="+userId);
            log.debug("get withExt="+withExt);
        }
        PUser user = dao.selectOne(Mapper.PUserMapper, "selectByPrimaryKey", userId);
        JSONObject rtn = (JSONObject)JSONObject.toJSON(user);
        if (withExt) {
            PUserExt ext = dao.selectOne("PUserExtMapper", "selectByPrimaryKey", userId);
            if (ext!=null) {
                rtn.putAll((JSONObject)JSONObject.toJSON(ext));
            }
            Map<String, Object> paramMap = new HashMap<String, Object>();
            paramMap.put(Const.TENANT_ID, tenantId);
            paramMap.put("userId", userId);
            paramMap.put("relationType", "01");
            List<PUserExtref> extrefs = dao.selectList("PUserExtrefMapper", "selectByUserId", paramMap);
            if (extrefs!=null && extrefs.size()>0) {
                JSONObject extrefsJo = new JSONObject();
                for (PUserExtref extref:extrefs) {
                    extrefsJo.put(extref.getRelationType(), JSONObject.toJSON(extref));
                }
                rtn.put("extrefs", extrefsJo);
            }
        }
        return rtn;
    }

    /**
     * Get usr profile info, used in profile self-management
     * @param request
     * @param withExt
     * @return
     */
    @RequestMapping(value="/api/v1/user/current", method= RequestMethod.GET)
    public JSONObject getCurrent(HttpServletRequest request, @RequestParam("withExt")Boolean withExt) {
        Map<String, String> userDetail = (Map<String, String>)SecurityContextHolder.getContext().getAuthentication().getDetails();
        String sln = userDetail.get(Const.LOGINNAME);
        if (log.isDebugEnabled()) {
            log.debug("getCurrent request session loginName="+sln);
            log.debug("getCurrent request withExt="+withExt);
        }
        PUser user = dao.selectOne(Mapper.PUserMapper, "selectByPrimaryKey", sln);
        JSONObject rtn = (JSONObject)JSONObject.toJSON(user);
        if (withExt) {
            PUserExt ext = dao.selectOne("PUserExtMapper", "selectByPrimaryKey", sln);
            if (ext!=null) {
                rtn.putAll((JSONObject)JSONObject.toJSON(ext));
            }
        }

        return rtn;
    }

    /**
     * User register
     * @param request
     * @return
     */
    @RequestMapping(value="/openapi/v1/user/register", method= RequestMethod.POST)
    @Transactional(EngineConst.TRANSACTION_MANAGER)
    public JSONObject register(HttpServletRequest request) {
        String inviteCode = request.getParameter("inviteCode");
        String loginName = request.getParameter("loginName");
        String password = request.getParameter("password");
        String email = request.getParameter("email");
        String mobile = request.getParameter("mobile");
        String realName = request.getParameter("realName");
        if (log.isDebugEnabled()) {
            log.debug("register request inviteCode="+inviteCode);
            log.debug("register request loginName="+loginName);
            log.debug("register request password="+password);
            log.debug("register request email="+email);
            log.debug("register request mobile="+mobile);
            log.debug("register request realName="+realName);
        }

        JSONObject rtn = new JSONObject();

        //get tenant
        PTenant tenant = dao.selectOne("PTenantMapper", "selectByInviteCode", inviteCode);
        Map countMap = dao.selectOne(Mapper.PUserMapper, "countAccountForTenant", tenant.getTenantId());
        if (!"1".equals(tenant.getStatus())) {
            rtn.put("errorCode", "COMPANY_ACCOUNT_NOT_ACTIVE");
            return rtn;
        }
        if ((long)countMap.get("COUNT")>=tenant.getAcount()) {
            rtn.put("errorCode", "MAX_ACTIVE_ACCOUNT_EXCEED");
            return rtn;
        }

        PUser user = new PUser();
        user.setTenantId(tenant.getTenantId());
        user.setUserId(loginName);
        user.setLoginName(loginName);
        user.setStatus("00"); //人员状态 00-新注册 在职10 休假11 离职12
        user.setRealName(realName);
        user.setDisplayName(realName+"("+loginName+")");
        user.setPassword(DigestUtils.sha256Hex(password));
        user.setEmail(email);
        user.setMobile(mobile);
        user.setUserType("0"); //人员类型 普通员工0 外协人员1
        user.setIsvalid("1"); //是否有效 是1 否0

        int rs = dao.insert(Mapper.PUserMapper, "insertSelective", user);

        //发送激活邮件
        PNotifyOld notify = new PNotifyOld();
        notify.setTenantId(tenant.getTenantId());
        notify.setId(UUID.randomUUID().toString());
        notify.setTitle("【BPM云】请激活您的帐号");
        notify.setContent("感谢您的注册，您的帐号(<b><font color=\"blue\">" + loginName + "</font></b>)需要激活！<br/>"
                +"请点击下面链接进行激活，建议您首次登录后修改密码，祝您使用愉快！");
        String activateUrl = bpmp.getSiteUrl() + "/pages/profile/account_activate.html?"+ AES.encrypt(loginName);
        notify.setReadUrl(activateUrl);
        notify.setSender(bpmp.getServiceMailAddress());
        notify.setSenderName("【BPM云】服务");
        notify.setReceiver(loginName);
        notify.setReceiverName(realName);
        Date now = DateUtil.getGMTDate();
        notify.setCreateTime(now);
        notify.setScheduleTime(now);
        notify.setType("0");
        notify.settType("U");
        notify.setStatus("0");
        notify.setDestination(email);
        rs += dao.insert("PNotifyOldMapper", "insertSelective", notify);

        rtn.put("result", rs);

        //记录日志
        oplog.bizlog(tenant.getTenantId()>0 ? String.valueOf(tenant.getTenantId()) : null,
                loginName, user.getDisplayName(), null, Oplog.OP.REGISTER, Oplog.CODE.PLATFORM, "");

        return rtn;
    }

    /**
     * update user basic info
     * @param request
     * @param user
     * @return
     */
    @RequestMapping(value="/api/v1/user/update", method= RequestMethod.POST)
    public JSONObject update(HttpServletRequest request, PUser user) {
        Map<String, String> userDetail = (Map<String, String>)SecurityContextHolder.getContext().getAuthentication().getDetails();
        String sln = userDetail.get(Const.LOGINNAME);
        String sdn = userDetail.get(Const.DISPLAYNAME);
        String oldPwd = request.getParameter("oldPwd");
        if (log.isDebugEnabled()) {
            log.debug("update request session loginName="+sln);
            log.debug("update request session displayName="+sdn);
            log.debug("update request oldPwd="+oldPwd);
        }

        return ups.update(sln, sdn, user, oldPwd);
    }

    /**
     * update user extension info
     * @param request
     * @param userExt
     * @return
     */
    @RequestMapping(value="/api/v1/user/updateExt", method= RequestMethod.POST)
    public JSONObject updateExt(HttpServletRequest request, PUserExt userExt) {
        Map<String, String> userDetail = (Map<String, String>)SecurityContextHolder.getContext().getAuthentication().getDetails();
        String sln = userDetail.get(Const.LOGINNAME);
        String sdn = userDetail.get(Const.DISPLAYNAME);
        if (log.isDebugEnabled()) {
            log.debug("update request session loginName="+sln);
            log.debug("update request session displayName="+sdn);
        }

        return ups.updateExt(sln, sdn, userExt);
    }

    /**
     * Delete an user
     * @param request
     * @param userId
     * @return
     */
    @RequestMapping(value="/api/v1/user/{userId}", method= RequestMethod.DELETE)
    public JSONObject delete(HttpServletRequest request, @PathVariable("userId")String userId) {
        Map<String, String> userDetail = (Map<String, String>)SecurityContextHolder.getContext().getAuthentication().getDetails();
        String sln = userDetail.get(Const.LOGINNAME);
        String sdn = userDetail.get(Const.DISPLAYNAME);
        if (log.isDebugEnabled()) {
            log.debug("delete request session loginName="+sln);
            log.debug("delete request session displayName="+sdn);
            log.debug("delete request userId="+userId);
        }

        return ups.delete(sln, sdn, userId);
    }

    /**
     * check attr of a tenant
     * @return
     */
    @RequestMapping(value="/openapi/v1/user/checkAttr",
            produces = "plain/text")
    public String checkAttr(HttpServletRequest request) {
        String attrName = request.getParameterNames().nextElement();
        String value = request.getParameter(attrName);
        String userId = request.getParameter("userId");
        String reverse = request.getParameter("reverse");   //反向输出测试
        if (log.isDebugEnabled()) {
            log.debug("checkAttr attrName="+attrName);
            log.debug("checkAttr value="+value);
            log.debug("checkAttr userId="+userId);
            log.debug("checkAttr reverse="+reverse);
        }
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("userId", userId);
        paramMap.put("value", value);
        Map rs = dao.selectOne(Mapper.PUserMapper, "checkAttr"+ StringUtils.capitalize(attrName), paramMap);
        if (log.isDebugEnabled()) {
            log.debug("checkAttr rs="+rs);
        }
        for (Object key : rs.keySet()) {
            log.debug(key.getClass().getName());
        }
        long count = (long) rs.get("COUNT");
        boolean r = (reverse==null) ? count>0 : count==0;
        return r ? "false" : "true";
    }

    /**
     * activate a tenant
     * @return
     */
    @RequestMapping(value="/openapi/v1/user/activate/{userIdStr}",
            method= RequestMethod.GET)
    public JSONObject activate(HttpServletRequest request,
                           @PathVariable("userIdStr")String userIdStr) {
        String userId = AES.decrypt(userIdStr);
        if (log.isDebugEnabled()) {
            log.debug("activate userId="+userId);
        }
        PUser user = dao.selectOne(Mapper.PUserMapper, "selectByPrimaryKey", userId);

        JSONObject rtn = new JSONObject();
        rtn.put("siteUrl", bpmp.getSiteUrl());

        if (!"00".equalsIgnoreCase(user.getStatus())) {
            rtn.put("errorCode", "NOT_NEW_ACCOUNT");
        } else {
            user.setStatus("10");
            int rs = dao.update(Mapper.PUserMapper, "updateByPrimaryKeySelective", user);
            rtn.put("result", rs);
        }
        return rtn;
    }

    /**
     * change password
     * @return
     */
    @RequestMapping(value="/api/v1/user/changePwd",
            method= RequestMethod.POST)
    public JSONObject changePwd(HttpServletRequest request) {
        Map<String, String> userDetail = (Map<String, String>)SecurityContextHolder.getContext().getAuthentication().getDetails();
        String sln = userDetail.get(Const.LOGINNAME);
        String sdn = userDetail.get(Const.DISPLAYNAME);
        String oldPwd = request.getParameter("oldPwd");
        String newPwd = request.getParameter("newPwd");
        if (log.isDebugEnabled()) {
            log.debug("changePwd request session loginName="+sln);
            log.debug("changePwd request session displayName="+sdn);
            log.debug("changePwd request oldPwd="+oldPwd);
        }

        return ups.changePwd(sln, sdn, newPwd, oldPwd);
    }

    /**
     * reset password
     * @return
     */
    @RequestMapping(value="/openapi/v1/user/resetPwd",
            method= RequestMethod.POST)
    public JSONObject resetPwd(HttpServletRequest request) {
        String email = request.getParameter("email");
        if (log.isDebugEnabled()) {
            log.debug("resetPwd email="+email);
        }
        PUser user = dao.selectOne(Mapper.PUserMapper, "selectByEmail", email);

        JSONObject rtn = new JSONObject();

        if (user==null) {
            rtn.put("errorCode", "NOT_AN_ACCOUNT");
            return rtn;
        }

        if ("00".equalsIgnoreCase(user.getStatus())) {
            rtn.put("errorCode", "NOT_ACTIVATED_ACCOUNT");
            return rtn;
        }

        String newPwd = AES.random(6);
        user.setPassword(DigestUtils.sha256Hex(newPwd));
        int rs = dao.update(Mapper.PUserMapper, "updateByPrimaryKeySelective", user);

        //发送重置邮件
        PNotifyOld notify = new PNotifyOld();
        notify.setTenantId(user.getTenantId());
        notify.setId(UUID.randomUUID().toString());
        notify.setTitle("【BPM云】您已成功重置密码");
        notify.setContent("您的帐号(<b><font color=\"blue\">" + user.getLoginName() + "</font></b>)密码已经被成功重置为(<b><font color=\"blue\">" + newPwd + "</font></b>)。<br/>"
                +"请点击下面链接进行登录，建议您登录后修改密码，祝您使用愉快！");
        notify.setReadUrl(bpmp.getSiteUrl());
        notify.setSender(bpmp.getServiceMailAddress());
        notify.setSenderName("【BPM云】服务");
        notify.setReceiver(user.getLoginName());
        notify.setReceiverName(user.getRealName());
        Date now = DateUtil.getGMTDate();
        notify.setCreateTime(now);
        notify.setScheduleTime(now);
        notify.setType("0");
        notify.settType("U");
        notify.setStatus("0");
        notify.setDestination(email);
        rs += dao.insert("PNotifyOldMapper", "insertSelective", notify);

        rtn.put("result", rs);
        return rtn;
    }

    /**
     * Get admin menu after login
     * @param request
     * @return
     */
    @RequestMapping(value="/api/v1/user/adminMenu", method= RequestMethod.GET)
    public JSONObject getAdminMenu(HttpServletRequest request) {
        Map<String, String> userDetail = (Map<String, String>)SecurityContextHolder.getContext().getAuthentication().getDetails();
        String tenantId = userDetail.get(Const.TENANT_ID);
        String loginName = userDetail.get(Const.LOGINNAME);
        if (log.isDebugEnabled()) {
            log.debug("getAdminMenu request session tenantId="+tenantId);
            log.debug("getAdminMenu request session loginName="+loginName);
        }
        JSONObject rtn = new JSONObject();
        JSONArray menus = ups.getUserAdminMenu(tenantId, loginName);
        rtn.put("menus", menus);

        //获取是否启用oss avatar，同时在todoBpdGroupCount
        String ossAvatar = env.getProperty("oss.avatar.enabled","false");
        if (Boolean.parseBoolean(ossAvatar)) {
            rtn.put(Const.LOGINNAME, loginName);
            rtn.put("avatarEnabled", true);
            rtn.put("avatarType", "oss");
            rtn.put("avatarOssUrlPrefix", avs.getAvatarUrlPrefix(userDetail.get(Const.TENANT_ID)));
        }

        return rtn;
    }

    /**
     * Get admin menu after login
     * @param request
     * @return
     */
    @RequestMapping(value="/api/v1/user/portalMenu", method= RequestMethod.GET)
    public JSONObject getPortalMenu(HttpServletRequest request) {
        Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
        String tenantId = userDetail.get(Const.TENANT_ID);
        String loginName = userDetail.get(Const.LOGINNAME);
        if (log.isDebugEnabled()) {
            log.debug("getPortalMenu request session tenantId="+tenantId);
            log.debug("getPortalMenu request session loginName="+loginName);
        }
        JSONObject rtn = ups.getUserPortalMenu(tenantId, loginName);

        //获取是否启用oss avatar，同时在todoBpdGroupCount
        String ossAvatar = env.getProperty("oss.avatar.enabled","false");
        if (Boolean.parseBoolean(ossAvatar)) {
            rtn.put(Const.LOGINNAME, loginName);
            rtn.put("avatarEnabled", true);
            rtn.put("avatarType", "oss");
            rtn.put("avatarOssUrlPrefix", avs.getAvatarUrlPrefix(userDetail.get(Const.TENANT_ID)));
        }

        return rtn;
    }

    /**
     * 上传用户头像
     * @param request
     * @param param
     * @param imageFile
     * @return
     */
    @PostMapping(value="/api/v1/user/uploadAvatar")
    public JSONObject uploadAvatar(HttpServletRequest request,
                                    @RequestParam Map<String, String> param,
                                   @RequestParam("file") MultipartFile imageFile) {
        Map<String, String> userDetail = (Map<String, String>) SecurityContextHolder.getContext().getAuthentication().getDetails();
        String tenantId = userDetail.get(Const.TENANT_ID);
        String loginName = userDetail.get(Const.LOGINNAME);
        if (log.isDebugEnabled()) {
            log.debug("uploadAvatar param=" + param);
            log.debug("uploadAvatar imageFile=" + imageFile);
        }
        try {
            JSONObject rtn = avs.uploadAvatar(tenantId, loginName, param, imageFile.getInputStream());
            return rtn;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}
